package org.jfuse;

import java.io.*;
import java.util.Date;
import java.util.logging.*;

public class Fuse 
{
	private static Logger logger = Logger.getLogger(Fuse.class.getName());
	
	private static FuseHandler handler = null;

	public static synchronized int main(String[] args, FuseHandler handler)
	{
		// suggested: -o allow_other, -f
		Fuse.handler = handler;
		return fuse_main(args);
	}
	
	private static String fuse_readlink(String path) throws FuseResult
	{
		logger.info("readlink("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		return handler.readlink(path);
	}	

	private static void fuse_mkdir(String path, int mode) throws FuseResult
	{
		logger.info("mkdir("+path+","+mode+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.mkdir(path, mode);
	}
	
	private static void fuse_unlink(String path) throws FuseResult
	{
		logger.info("unlink("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.unlink(path);
	}
	
	private static void fuse_rmdir(String path) throws FuseResult
	{
		logger.info("rmdir("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.rmdir(path);
	}
	
	private static void fuse_symlink(String from, String to) throws FuseResult
	{
		logger.info("symlink("+from+","+to+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.symlink(from, to);
	}

	private static void fuse_rename(String from, String to) throws FuseResult
	{
		logger.info("rename("+from+","+to+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.rename(from, to);
	}

	private static void fuse_link(String from, String to) throws FuseResult
	{
		logger.info("link("+from+","+to+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.link(from, to);
	}

	private static void fuse_chmod(String path, int mode) throws FuseResult
	{
		logger.info("chmod("+path+","+mode+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.chmod(path, mode);
	}
		
	private static void fuse_chown(String path, int uid, int gid) throws FuseResult
	{
		logger.info("chown("+path+","+uid+","+gid+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.chown(path, uid, gid);
	}
		
	private static void fuse_truncate(String path, long size) throws FuseResult
	{
		logger.info("truncate("+path+","+size+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.truncate(path, size);
	}
		
	private static void fuse_open(String path) throws FuseResult
	{
		logger.info("open("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.open(path);
	}
		
	private static int fuse_read(String path, byte[] buffer, long offset) throws FuseResult
	{
		logger.info("read("+path+","+buffer.length+","+offset+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		return handler.read(path, buffer, offset);
	}
		
	private static int fuse_write(String path, byte[] buffer, long offset) throws FuseResult
	{
		logger.info("write("+path+","+buffer.length+","+offset+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		return handler.write(path, buffer, offset);
	}
		
	private static FuseStatVFS fuse_statfs(String path) throws FuseResult
	{
		logger.info("statfs("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		return handler.statfs(path);
	}
		
	private static void fuse_opendir(String path) throws FuseResult
	{
		logger.info("opendir("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.opendir(path);
	}	
	
	private static String[] fuse_readdir(String path) throws FuseResult
	{
		logger.info("readdir("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		return handler.readdir(path);
	}
	
	private static void fuse_create(String path, int mode) throws FuseResult
	{
		logger.info("create("+path+","+mode+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.create(path, mode);
	}
		
	private static FuseStat fuse_getattr(String path) throws FuseResult
	{
		logger.info("getattr("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		return handler.getattr(path);
	}

	private static void fuse_utime(String path, long actime, long modtime) throws FuseResult
	{
		logger.info("utime("+path+")");
		if (handler == null) throw new FuseResult(FuseResult.ENOSYS);
		handler.utime(path, actime, modtime);
	}
	
	private static native int fuse_main(String[] args);
	
	static {
		try {
			String libName = "org_jfuse_Fuse";
			String suffix = System.mapLibraryName(libName);
			suffix = suffix.substring(suffix.lastIndexOf('.'));
			File tempFile = File.createTempFile("jfuse", suffix);
			String platform = System.getProperty("os.name").replace(" ", "_") + "_" + System.getProperty("os.arch").replace(" ", "_");	
			String jniLib = platform + "_" + System.mapLibraryName(libName);
			logger.info("storing jni library for platform " + platform + " as " + tempFile + " for lib name " + libName + " from resource " + jniLib);
			InputStream is = Fuse.class.getResourceAsStream(jniLib);
			if (is == null) {
				throw new RuntimeException("no jni library bundled for platform " + platform);
			}
			FileOutputStream os = new FileOutputStream(tempFile);
			byte[] buf = new byte[8192];
			while (true) {
				int cnt = is.read(buf);
				if (cnt <= 0) break;
				os.write(buf, 0, cnt);
			}
			os.close();
			is.close();
			tempFile.deleteOnExit();
			System.load(tempFile.getAbsolutePath());
		} catch (Exception e) {
			throw new RuntimeException("failed to load fuse library", e);
		}
	}
	
}
